home *** CD-ROM | disk | FTP | other *** search
- // This is part of the iostream library, providing input/output for C++.
- // Copyright (C) 1991, 1992 Per Bothner.
- //
- // This library is free software; you can redistribute it and/or
- // modify it under the terms of the GNU Library General Public
- // License as published by the Free Software Foundation; either
- // version 2 of the License, or (at your option) any later version.
- //
- // This library is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- // Library General Public License for more details.
- //
- // You should have received a copy of the GNU Library General Public
- // License along with this library; if not, write to the Free
- // Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- #define _STREAM_COMPAT
- #ifdef __GNUG__
- #pragma implementation
- #endif
- #include <ioprivat.h>
- #include <string.h>
-
- // Return minimum _pos markers
- // Assumes the current get area is the main get area.
- long streambuf::_least_marker()
- {
- long least_so_far = _egptr - _eback;
- for (register streammarker *mark = _markers;
- mark != NULL; mark = mark->_next)
- if (mark->_pos < least_so_far)
- least_so_far = mark->_pos;
- return least_so_far;
- }
-
- // Switch current get area from backup buffer to (start of) main get area.
-
- void streambuf::switch_to_main_get_area()
- {
- char *tmp;
- _flags &= ~_S_IN_BACKUP;
- // Swap _egptr and _other_egptr.
- tmp= _egptr; _egptr= _other_egptr; _other_egptr= tmp;
- // Swap _eback and _other_gbase.
- tmp= _eback; _eback = _other_gbase; _other_gbase = tmp;
- _gptr = _eback;
- }
-
- // Switch current get area from main get area to (end of) backup area.
-
- void streambuf::switch_to_backup_area()
- {
- char *tmp;
- _flags |= _S_IN_BACKUP;
- // Swap _egptr and _other_egptr.
- tmp = _egptr; _egptr = _other_egptr; _other_egptr = tmp;
- // Swap _gbase and _other_gbase.
- tmp = _eback; _eback = _other_gbase; _other_gbase = tmp;
- _gptr = _egptr;
- }
-
- int streambuf::switch_to_get_mode()
- {
- if (_pptr > _pbase)
- if (overflow(EOF) == EOF)
- return EOF;
- if (in_backup()) {
- _eback = _aux_limit;
- }
- else {
- _eback = _base;
- if (_pptr > _egptr)
- _egptr = _pptr;
- }
- _gptr = _pptr;
-
- setp(_gptr, _gptr);
-
- _flags &= ~_S_CURRENTLY_PUTTING;
- return 0;
- }
-
- void streambuf::free_backup_area()
- {
- if (in_backup())
- switch_to_main_get_area(); // Just in case.
- delete [] _other_gbase;
- _other_gbase = NULL;
- _other_egptr = NULL;
- _aux_limit = NULL;
- }
-
- #if 0
- int streambuf::switch_to_put_mode()
- {
- _pbase = _gptr;
- _pptr = _gptr;
- _epptr = in_backup() ? _egptr : _ebuf; // wrong if line- or un-buffered?
-
- _gptr = _egptr;
- _eback = _egptr;
-
- _flags |= _S_CURRENTLY_PUTTING;
- return 0;
- }
- #endif
-
- #ifdef _G_FRIEND_BUG
- int __underflow(register streambuf *sb) { return __UNDERFLOW(sb); }
- int __UNDERFLOW(register streambuf *sb)
- #else
- int __underflow(register streambuf *sb)
- #endif
- {
- if (sb->put_mode())
- if (sb->switch_to_get_mode() == EOF) return EOF;
- if (sb->_gptr < sb->_egptr)
- return *(unsigned char*)sb->_gptr;
- if (sb->in_backup()) {
- sb->switch_to_main_get_area();
- if (sb->_gptr < sb->_egptr)
- return *sb->_gptr;
- }
- if (sb->have_markers()) {
- // Append [_gbase.._egptr] to backup area.
- long least_mark = sb->_least_marker();
- // needed_size is how much space we need in the backup area.
- long needed_size = (sb->_egptr - sb->_eback) - least_mark;
- long current_Bsize = sb->_other_egptr - sb->_other_gbase;
- long avail; // Extra space available for future expansion.
- if (needed_size > current_Bsize) {
- avail = 0; // 100 ?? FIXME
- char *new_buffer = new char[avail+needed_size];
- if (least_mark < 0) {
- memcpy(new_buffer + avail,
- sb->_other_egptr + least_mark,
- -least_mark);
- memcpy(new_buffer +avail - least_mark,
- sb->_eback,
- sb->_egptr - sb->_eback);
- }
- else
- memcpy(new_buffer + avail,
- sb->_eback + least_mark,
- needed_size);
- delete [] sb->_other_gbase;
- sb->_other_gbase = new_buffer;
- sb->_other_egptr = new_buffer + avail + needed_size;
- }
- else {
- avail = current_Bsize - needed_size;
- if (least_mark < 0) {
- memmove(sb->_other_gbase + avail,
- sb->_other_egptr + least_mark,
- -least_mark);
- memcpy(sb->_other_gbase + avail - least_mark,
- sb->_eback,
- sb->_egptr - sb->_eback);
- }
- else if (needed_size > 0)
- memcpy(sb->_other_gbase + avail,
- sb->_eback + least_mark,
- needed_size);
- }
- // FIXME: Dubious arithmetic if pointers are NULL
- sb->_aux_limit = sb->_other_gbase + avail;
- // Adjust all the streammarkers.
- long delta = sb->_egptr - sb->_eback;
- for (register streammarker *mark = sb->_markers;
- mark != NULL; mark = mark->_next)
- mark->_pos -= delta;
- }
- else if (sb->have_backup())
- sb->free_backup_area();
- return sb->underflow();
- }
-
- #ifdef _G_FRIEND_BUG
- int __overflow(register streambuf *sb, int c) { return __OVERFLOW(sb, c); }
- int __OVERFLOW(register streambuf *sb, int c)
- #else
- int __overflow(streambuf* sb, int c)
- #endif
- {
- return sb->overflow(c);
- }
-
- #ifdef atarist
- // for the atari we take a hit here so that bin/text modes are taken care of
- // automatically by sputc/sbumpc
-
- size_t streambuf::sputn(const char* s, size_t n) // OPTIMIZE THIS!
- {
- size_t count = 0;
-
- if(((long)n) < 0) return 0;
-
- for (; count < n; count++) {
- if (sputc(*s++) == EOF)
- break;
- }
- return count;
- }
-
- size_t streambuf::sgetn(char* s, size_t n) // OPTIMIZE THIS!
- {
- size_t count = 0;
- for (; count < n; count++) {
- int ch = sbumpc();
- if (ch == EOF)
- break;
- *s++ = ch;
- }
- return count;
- }
-
- size_t streambuf::ignore(size_t n)
- {
- size_t more = n;
- int ch;
-
- while(more && ((ch = sbumpc() != EOF))) more--;
- return n - more;
- }
-
- #else
- size_t streambuf::sputn(register const char* s, size_t n)
- {
- if (n <= 0)
- return 0;
- register size_t more = n;
- for (;;) {
- size_t count = _epptr - _pptr; // Space available.
- if (count > 0) {
- if (count > more)
- count = more;
- if (count > 20) {
- memcpy(_pptr, s, count);
- s += count;
- _pptr += count;
- }
- else if (count <= 0)
- count = 0;
- else {
- register char *p = _pptr;
- for (register long i = count; --i >= 0; ) *p++ = *s++;
- _pptr = p;
- }
- more -= count;
- }
- if (more == 0 || __overflow(this, (unsigned char)*s++) == EOF)
- break;
- more--;
- }
- return n - more;
- }
-
-
- size_t streambuf::sgetn(char* s, size_t n)
- {
- register size_t more = n;
- for (;;) {
- size_t count = _egptr - _gptr; // Data available.
- if (count > 0) {
- if (count > more)
- count = more;
- if (count > 20) {
- memcpy(s, _gptr, count);
- s += count;
- _gptr += count;
- }
- else if (count <= 0)
- count = 0;
- else {
- register char *p = _gptr;
- for (register long i = count; --i >= 0; ) *s++ = *p++;
- _gptr = p;
- }
- more -= count;
- }
- if (more == 0 || __underflow(this) == EOF)
- break;
- }
- return n - more;
- }
-
- size_t streambuf::ignore(size_t n)
- {
- register size_t more = n;
- for (;;) {
- long count = _egptr - _gptr; // Data available.
- if (count > 0) {
- if (count > more)
- count = more;
- _gptr += count;
- more -= count;
- }
- if (more == 0 || __underflow(this) == EOF)
- break;
- }
- return n - more;
- }
- #endif /* atari */
-
- int streambuf::padn(char pad, int count)
- {
- #define PADSIZE 16
- static char const blanks[PADSIZE] =
- {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
- static char const zeroes[PADSIZE] =
- {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
- char padbuf[PADSIZE];
- const char *padptr;
- register int i;
-
- if (pad == ' ')
- padptr = blanks;
- else if (pad == '0')
- padptr = zeroes;
- else {
- for (i = PADSIZE; --i >= 0; ) padbuf[i] = pad;
- padptr = padbuf;
- }
- for (i = count; i >= PADSIZE; i -= PADSIZE)
- if (sputn(padptr, PADSIZE) != PADSIZE)
- return EOF;
- if (i > 0 && sputn(padptr, i) != i)
- return EOF;
- return pad;
- }
-
- int streambuf::sync()
- {
- if (gptr() == egptr() && pptr() == pbase())
- return 0;
- return EOF;
- }
-
- int streambuf::pbackfail(int c)
- {
- return EOF;
- }
-
- int streambuf::ungetfail()
- {
- if (seekoff(-1, ios::cur, ios::in) == EOF)
- return EOF;
- return sgetc();
- }
-
- streambuf* streambuf::setbuf(char* p, size_t len)
- {
- if (sync() == EOF)
- return NULL;
- if (p == NULL || len == 0) {
- unbuffered(1);
- setb(_shortbuf, _shortbuf+1, 0);
- }
- else {
- unbuffered(0);
- setb(p, p+len, 0);
- }
- setp(0, 0);
- setg(0, 0, 0);
- return this;
- }
-
- streampos streambuf::seekpos(streampos pos, int mode)
- {
- return seekoff(pos, ios::beg, mode);
- }
-
- void streambuf::setb(char* b, char* eb, int a)
- {
- if (_base && !(_flags & _S_USER_BUF))
- FREE_BUF(_base);
- _base = b;
- _ebuf = eb;
- if (a)
- _flags &= ~_S_USER_BUF;
- else
- _flags |= _S_USER_BUF;
- }
-
- #ifdef atarist
- extern "C" { extern unsigned long __DEFAULT_BUFSIZ__; }
-
- int streambuf::doallocate()
- {
- char *buf = malloc((size_t)__DEFAULT_BUFSIZ__);
- if (buf == NULL)
- return EOF;
- setb(buf, buf+__DEFAULT_BUFSIZ__, 1);
- return 1;
- }
- #else
- int streambuf::doallocate()
- {
- char *buf = ALLOC_BUF(_G_BUFSIZ);
- if (buf == NULL)
- return EOF;
- setb(buf, buf+_G_BUFSIZ, 1);
- return 1;
- }
- #endif
-
- void streambuf::doallocbuf()
- {
- if (base() || (!unbuffered() && doallocate() != EOF)) return;
- setb(_shortbuf, _shortbuf+1, 0);
- }
-
- #ifdef atarist
- extern "C" extern int __default_mode__;
- #endif
-
- streambuf::streambuf(long flags)
- {
- #ifdef atarist
- if(!(flags & _IOS_TEXT))
- _flags = _IO_MAGIC | ((__default_mode__)? _S_IS_BINARY : 0) | flags;
- else
- _flags = _IO_MAGIC | (flags & (~_S_IS_BINARY));
- #else
- _flags = _IO_MAGIC|flags;
- #endif
- _base = NULL;
- _ebuf = NULL;
- _eback = NULL;
- _gptr = NULL;
- _egptr = NULL;
- _pbase = NULL;
- _pptr = NULL;
- _epptr = NULL;
- _chain = NULL; // Not necessary.
-
- _other_gbase = NULL;
- _aux_limit = NULL;
- _other_egptr = NULL;
- _markers = NULL;
- _cur_column = 0;
- }
-
- streambuf::~streambuf()
- {
- if (_base && !(_flags & _S_USER_BUF))
- FREE_BUF(_base);
-
- for (register streammarker *mark = _markers;
- mark != NULL; mark = mark->_next)
- mark->_sbuf = NULL;
-
- }
-
- streampos
- streambuf::seekoff(streamoff, _seek_dir, int mode /*=ios::in|ios::out*/)
- {
- return EOF;
- }
-
- int streambuf::sputbackc(char c)
- {
- if (gptr() <= eback()) return pbackfail(c);
- gbump(-1);
- // Don't write into the get buffer if we don't have to.
- if (*gptr() != c)
- *gptr() = c;
- return (unsigned char)c;
- }
-
- int streambuf::sungetc()
- {
- if (gptr() > eback()) {
- gbump(-1);
- return (unsigned char)*gptr();
- }
- else
- return ungetfail();
- }
-
- #if 0 /* Work in progress */
- void streambuf::collumn(int c)
- {
- if (c == -1)
- _collumn = -1;
- else
- _collumn = c - (_pptr - _pbase);
- }
- #endif
-
-
- int streambuf::get_column()
- {
- if (_cur_column)
- return __adjust_column(_cur_column - 1, pbase(), pptr() - pbase());
- return -1;
- }
-
- int streambuf::set_column(int i)
- {
- overflow(EOF);
- _cur_column = i+1;
- return 0;
- }
-
- int streambuf::flush_all()
- {
- int result = 0;
- for (streambuf *sb = _list_all; sb != NULL; sb = sb->xchain())
- if (sb->overflow(EOF) == EOF)
- result = EOF;
- return result;
- }
-
- void streambuf::flush_all_linebuffered()
- {
- for (streambuf *sb = _list_all; sb != NULL; sb = sb->xchain())
- if (sb->linebuffered())
- sb->overflow(EOF);
- }
-
- int backupbuf::underflow()
- {
- return EOF;
- }
-
- int backupbuf::overflow(int c)
- {
- return EOF;
- }
-
- streammarker::streammarker(streambuf *sb)
- {
- _sbuf = sb;
- if (!(sb->xflags() & _S_IS_BACKUPBUF)) {
- set_streampos(sb->seekoff(0, ios::cur, ios::in));
- _next = 0;
- }
- else {
- if (sb->put_mode())
- sb->switch_to_get_mode();
- if (((backupbuf*)sb)->in_backup())
- set_offset(sb->_gptr - sb->_egptr);
- else
- set_offset(sb->_gptr - sb->_eback);
-
- // Should perhaps sort the chain?
- _next = ((backupbuf*)sb)->_markers;
- ((backupbuf*)sb)->_markers = this;
- }
- }
-
- streammarker::~streammarker()
- {
- if (saving()) {
- // Unlink from sb's chain.
- register streammarker **ptr = &((backupbuf*)_sbuf)->_markers;
- for (; ; ptr = &(*ptr)->_next)
- if (*ptr == NULL)
- break;
- else if (*ptr == this) {
- *ptr = _next;
- return;
- }
- }
- #if 0
- if _sbuf has a backup area that is no longer needed, should we delete
- it now, or wait until underflow()?
- #endif
- }
-
- #define BAD_DELTA EOF
-
- int streammarker::delta(streammarker& other_mark)
- {
- if (_sbuf != other_mark._sbuf)
- return BAD_DELTA;
- if (saving() && other_mark.saving())
- return _pos - other_mark._pos;
- else if (!saving() && !other_mark.saving())
- return _spos - other_mark._spos;
- else
- return BAD_DELTA;
- }
-
- int streammarker::delta()
- {
- if (_sbuf == NULL)
- return BAD_DELTA;
- if (saving()) {
- int cur_pos;
- if (_sbuf->in_backup())
- cur_pos = _sbuf->_gptr - _sbuf->_egptr;
- else
- cur_pos = _sbuf->_gptr - _sbuf->_eback;
- return _pos - cur_pos;
- }
- else {
- if (_spos == EOF)
- return BAD_DELTA;
- int cur_pos = _sbuf->seekoff(0, ios::cur);
- if (cur_pos == EOF)
- return BAD_DELTA;
- return _pos - cur_pos;
- }
- }
-
- int streambuf::seekmark(streammarker& mark, int delta = 0)
- {
- if (mark._sbuf != this)
- return EOF;
- if (!mark.saving()) {
- return seekpos(mark._spos, ios::in);
- }
- else if (mark._pos >= 0) {
- if (in_backup())
- switch_to_main_get_area();
- _gptr = _eback + mark._pos;
- }
- else {
- if (!in_backup())
- switch_to_backup_area();
- _gptr = _egptr + mark._pos;
- }
- return 0;
- }
-
- void streambuf::unsave_markers()
- {
- register streammarker *mark =_markers;
- if (_markers) {
- streampos offset = seekoff(0, ios::cur, ios::in);
- if (offset != EOF) {
- offset += eGptr() - Gbase();
- for ( ; mark != NULL; mark = mark->_next)
- mark->set_streampos(mark->_pos + offset);
- }
- else {
- for ( ; mark != NULL; mark = mark->_next)
- mark->set_streampos(EOF);
- }
- _markers = 0;
- }
-
- free_backup_area();
- }
-
- int backupbuf::pbackfail(int c)
- {
- // Need to handle a filebuf in write mode (switch to read mode). FIXME!
-
- if (have_backup() && !in_backup()) {
- switch_to_backup_area();
- }
- if (!have_backup()) {
- // No backup buffer: allocate one.
- // Use short buffer, if unused? (probably not) FIXME
- int backup_size = 128;
- _other_gbase = new char [backup_size];
- _other_egptr = _other_gbase + backup_size;
- _aux_limit = _other_egptr;
- switch_to_backup_area();
- }
- else if (gptr() <= eback()) {
- // Increase size of existing backup buffer.
- size_t new_size;
- size_t old_size = egptr() - eback();
- new_size = 2 * old_size;
- char* new_buf = new char [new_size];
- memcpy(new_buf+(new_size-old_size), eback(), old_size);
- delete [] eback();
- setg(new_buf, new_buf+(new_size-old_size), new_buf+new_size);
- _aux_limit = _gptr;
- }
- gbump(-1);
- if (*gptr() != c)
- *gptr() = c;
- return (unsigned char)c;
- }
-
- unsigned __adjust_column(unsigned start, const char *line, int count)
- {
- register const char *ptr = line + count;
- while (ptr > line)
- if (*--ptr == '\n')
- return line + count - ptr - 1;
- return start + count;
- }
-
-
- #if defined(linux)
- #define IO_CLEANUP ;
- #endif
-
- #ifdef IO_CLEANUP
- IO_CLEANUP
- #else
- struct __io_defs {
- __io_defs() { }
- ~__io_defs() { streambuf::flush_all(); }
- };
- __io_defs io_defs__;
- #endif
-